/**
 * @description 事件管理
 * @date 2024.9.10
 * @author wz
 * @midify 2025.3.13
 * @editor wz
 */

export type event_callback = (...params: any[]) => void

type eventNameType = string | number

/**
 * 不继承单例，像战斗可能需要独立的事件管理
 */
export class EventMgr {
    // 使用Map结构优化查找效率
    private eventMap: Map<eventNameType, Map<object, event_callback>> = new Map();
    // 对象到事件名的反向映射，便于批量移除
    private objToEvents: Map<object, Set<eventNameType>> = new Map();

    /**
     * 添加事件监听
     * @param obj 对象
     * @param eventName 监听名称 
     * @param eventFunc 监听方法
     */
    on(obj: object, eventName: eventNameType, eventFunc: event_callback) {
        // 获取或创建事件映射
        if (!this.eventMap.has(eventName)) {
            this.eventMap.set(eventName, new Map());
        }
        const objMap = this.eventMap.get(eventName)!;
        objMap.set(obj, eventFunc.bind(obj));

        // 维护反向映射
        if (!this.objToEvents.has(obj)) {
            this.objToEvents.set(obj, new Set());
        }
        this.objToEvents.get(obj)!.add(eventName);
    }

    /**
     * 移除一个事件
     * @param obj 对象
     * @param eventName 事件名
     */
    off(obj: object, eventName: eventNameType) {
        const objMap = this.eventMap.get(eventName);
        if (objMap) {
            objMap.delete(obj);
            // 如果该事件没有监听者了，清理Map
            if (objMap.size === 0) {
                this.eventMap.delete(eventName);
            }
        }

        // 更新反向映射
        const eventSet = this.objToEvents.get(obj);
        if (eventSet) {
            eventSet.delete(eventName);
            if (eventSet.size === 0) {
                this.objToEvents.delete(obj);
            }
        }
    }

    /**
     * 移除对象的所有事件
     * @param obj 对象
     */
    offAll(obj: object) {
        const eventSet = this.objToEvents.get(obj);
        if (!eventSet) return;

        // 从所有事件中移除该对象
        for (const eventName of eventSet) {
            const objMap = this.eventMap.get(eventName);
            if (objMap) {
                objMap.delete(obj);
                // 如果该事件没有监听者了，清理Map
                if (objMap.size === 0) {
                    this.eventMap.delete(eventName);
                }
            }
        }

        // 清理反向映射
        this.objToEvents.delete(obj);
    }

    /**
     * 触发事件
     * @param eventName 事件名
     * @param params 参数
     */
    emit(eventName: eventNameType, ...params: any[]) {
        const objMap = this.eventMap.get(eventName);
        if (!objMap) return;

        // 使用数组避免迭代过程中Map被修改的问题
        const callbacks = Array.from(objMap.values());
        for (const callback of callbacks) {
            try {
                callback(...params);
            } catch (error) {
                console.error(`Event callback error for ${eventName}:`, error);
            }
        }
    }

    /**
     * 检查是否有事件监听
     * @param eventName 事件名
     * @param obj 对象（可选）
     */
    has(eventName: eventNameType, obj?: object): boolean {
        const objMap = this.eventMap.get(eventName);
        if (!objMap) return false;

        if (obj) {
            return objMap.has(obj);
        }
        return objMap.size > 0;
    }

    /**
     * 清空所有事件
     */
    clear() {
        this.eventMap.clear();
        this.objToEvents.clear();
    }
}

export const eventMgr: EventMgr = new EventMgr();